using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;

namespace SymAutomate.PcInterfaceControl
{
    /// <summary>
    /// Handles PcinterfaceControl functions
    /// Error Numbers 420-499; Reference file ErrorNumbers.txt for more information.
    /// 420 Error: Report Number '%report number%' not found.
    /// 421 Error: FTP Transfer Failed %error log%.
    /// 422 Error: Invalid value for FtpTransfer Mode. Value values are ascii,binary.
    /// 423 Error: Batch Report not found for Jobfile %jobfilename%.
    /// 424 Error: No matching Reports found for Batch Report Sequence number '%sequence number%'.
    /// 425 Error: Ftp Transfer timed out.
    /// 430 Error: Letter File '%filename%' does not exist.
    /// 435 Error: Edit File location on Destination SYM already has a file. Delete the Edit File and try again. Aborting Process.
    /// 440 Error: Data File '%filename%' does not exist.
    /// </summary>
    class Driver : DriverBase, DriverInterface
    {
        private Parameters __Parameters;

        public Driver()
            : base()
        {
        }

        public Driver(ConsoleArguments _ConsoleArguments, HostTelnetConnection.Driver _HostTelnetConnectionDriver)
            : base(_HostTelnetConnectionDriver)
        {
            __Parameters = new Parameters(_ConsoleArguments, base.ConsoleHelpList);
        }

        /// <summary>
        /// Defines the command to function mapping;
        /// First parameter is what to expect as "command" from commmand line;
        /// Second parameter is the function name (case must match);
        /// </summary>
        public void PopulateCommandToFunctionMapping()
        {
            CommandToFunctionMapping.Add("ReportFileToPc".ToLower(), "ReportFileToPc");
            CommandToFunctionMapping.Add("LetterFileToPc".ToLower(), "LetterFileToPc");
            CommandToFunctionMapping.Add("DataFileToPc".ToLower(), "DataFileToPc");
            CommandToFunctionMapping.Add("PcToEditFile".ToLower(), "PcToEditFile");
            CommandToFunctionMapping.Add("PcToLetterFile".ToLower(), "PcToLetterFile");
            CommandToFunctionMapping.Add("PcToDataFile".ToLower(), "PcToDataFile");
            
        }

        /// <summary>
        /// Defines the help text for this driver
        /// </summary>
        public void PopulateConsoleHelp()
        {
            ConsoleHelp _ConsoleHelp = new ConsoleHelp("ReportFileToPc");
            _ConsoleHelp.Parameters.Add("JobFileName");
            _ConsoleHelp.Parameters.Add("ReportSequenceList");
            _ConsoleHelp.Parameters.Add("FtpServerIp");
            _ConsoleHelp.Parameters.Add("FtpServerUsername");
            _ConsoleHelp.Parameters.Add("FtpServerPassword");
            _ConsoleHelp.Parameters.Add("FtpServerTimeoutInSec");
            _ConsoleHelp.Parameters.Add("FtpServerTransferMode");
            _ConsoleHelp.Parameters.Add("FtpServerFolderPath");
            _ConsoleHelp.Parameters.Add("FtpDestinationFileNameTemplate");
            _ConsoleHelp.Parameters.Add("FtpJobFileReportTitle");
            ConsoleHelpList.Add(_ConsoleHelp);

            _ConsoleHelp = new ConsoleHelp("LetterFileToPc");
            _ConsoleHelp.Parameters.Add("FileName");
            _ConsoleHelp.Parameters.Add("FtpServerIp");
            _ConsoleHelp.Parameters.Add("FtpServerUsername");
            _ConsoleHelp.Parameters.Add("FtpServerPassword");
            _ConsoleHelp.Parameters.Add("FtpServerTimeoutInSec");
            _ConsoleHelp.Parameters.Add("FtpServerTransferMode");
            _ConsoleHelp.Parameters.Add("FtpServerFolderPath");
            ConsoleHelpList.Add(_ConsoleHelp);

            _ConsoleHelp = new ConsoleHelp("DataFileToPc");
            _ConsoleHelp.Parameters.Add("FileName");
            _ConsoleHelp.Parameters.Add("FtpServerIp");
            _ConsoleHelp.Parameters.Add("FtpServerUsername");
            _ConsoleHelp.Parameters.Add("FtpServerPassword");
            _ConsoleHelp.Parameters.Add("FtpServerTimeoutInSec");
            _ConsoleHelp.Parameters.Add("FtpServerTransferMode");
            _ConsoleHelp.Parameters.Add("FtpServerFolderPath");
            ConsoleHelpList.Add(_ConsoleHelp);

            _ConsoleHelp = new ConsoleHelp("PcToEditFile");
            _ConsoleHelp.Parameters.Add("FileName");
            _ConsoleHelp.Parameters.Add("FtpServerIp");
            _ConsoleHelp.Parameters.Add("FtpServerUsername");
            _ConsoleHelp.Parameters.Add("FtpServerPassword");
            _ConsoleHelp.Parameters.Add("FtpServerTimeoutInSec");
            _ConsoleHelp.Parameters.Add("FtpServerTransferMode");
            _ConsoleHelp.Parameters.Add("FtpServerFolderPath");
            ConsoleHelpList.Add(_ConsoleHelp);

            _ConsoleHelp = new ConsoleHelp("PcToLetterFile");
            _ConsoleHelp.Parameters.Add("FileName");
            _ConsoleHelp.Parameters.Add("FtpServerIp");
            _ConsoleHelp.Parameters.Add("FtpServerUsername");
            _ConsoleHelp.Parameters.Add("FtpServerPassword");
            _ConsoleHelp.Parameters.Add("FtpServerTimeoutInSec");
            _ConsoleHelp.Parameters.Add("FtpServerTransferMode");
            _ConsoleHelp.Parameters.Add("FtpServerFolderPath");
            ConsoleHelpList.Add(_ConsoleHelp);

            _ConsoleHelp = new ConsoleHelp("PcToDataFile");
            _ConsoleHelp.Parameters.Add("FileName");
            _ConsoleHelp.Parameters.Add("FtpServerIp");
            _ConsoleHelp.Parameters.Add("FtpServerUsername");
            _ConsoleHelp.Parameters.Add("FtpServerPassword");
            _ConsoleHelp.Parameters.Add("FtpServerTimeoutInSec");
            _ConsoleHelp.Parameters.Add("FtpServerTransferMode");
            _ConsoleHelp.Parameters.Add("FtpServerFolderPath");
            ConsoleHelpList.Add(_ConsoleHelp);
        }

        /// <summary>
        /// Implments PC Interface Control -> Report File to PC
        /// Moves the Report file(s) to PC using FTP
        /// </summary>
        public void ReportFileToPc()
        {
            string s = "";

            try
            {
                List<string> _ReportsList = new List<string>();

                if (!string.IsNullOrEmpty(__Parameters.JobFileName)) //use are moving the report(s) generated by the specified job
                {
                    //get the sequence number of the batch output file for the specified job name
                    HostTelnetConnectionDriver.Login();
                    string _BatchFileSequenceNumber = this.GetBatchSequenceNumber(__Parameters.JobFileName);

                    //get the reports that we need to move
                    HostTelnetConnectionDriver.Login();
                    _ReportsList = this.GetReportsForBatchSequence(_BatchFileSequenceNumber, __Parameters.FtpJobFileReportTitle);
                }
                else if (!string.IsNullOrEmpty(__Parameters.ReportSequenceList)) //we are moving the sequence numbers that are specified by the user
                {
                    _ReportsList = this.GetReportsForList(__Parameters.ReportSequenceList);
                }

                for (int i = 0; i < _ReportsList.Count; i++)
                {
                    HostTelnetConnectionDriver.Login();

                    HostTelnetConnectionDriver.TelnetSend("8" + GlobalParameters.TelnetSendEndOfCommand); //Management Menu
                    s = HostTelnetConnectionDriver.TelnetWaitFor("Menu Selection");
                    HostTelnetConnectionDriver.LogIncommingStream(s);

                    HostTelnetConnectionDriver.TelnetSend("2" + GlobalParameters.TelnetSendEndOfCommand); //PC Interface Control
                    s = HostTelnetConnectionDriver.TelnetWaitFor("Choice");
                    HostTelnetConnectionDriver.LogIncommingStream(s);

                    HostTelnetConnectionDriver.TelnetSend("0" + GlobalParameters.TelnetSendEndOfCommand); //Report File to PC
                    s = HostTelnetConnectionDriver.TelnetWaitFor("Report to Transfer");
                    HostTelnetConnectionDriver.LogIncommingStream(s);

                    HostTelnetConnectionDriver.TelnetSend(_ReportsList[i] + GlobalParameters.TelnetSendEndOfCommand); //Report to Transfer
                    s = HostTelnetConnectionDriver.TelnetWaitFor(new string[] { "Transfer Mode", "Report Not Found" });
                    s = HostTelnetConnectionDriver.LogIncommingStream(s);

                    if (s.Contains("Report Not Found")) throw new ReturnException("420 Error: Report Number '" + _ReportsList[i] + "' not found.");

                    HostTelnetConnectionDriver.TelnetSend("2" + GlobalParameters.TelnetSendEndOfCommand); //Transfer Mode
                    s = HostTelnetConnectionDriver.TelnetWaitFor("Transfer Reports Listed in This Report?");
                    HostTelnetConnectionDriver.LogIncommingStream(s);

                    HostTelnetConnectionDriver.TelnetSend("N" + GlobalParameters.TelnetSendEndOfCommand); //Transfer Reports Listed in This Report?
                    s = HostTelnetConnectionDriver.TelnetWaitFor("Remote Host or IP Addr");
                    HostTelnetConnectionDriver.LogIncommingStream(s);

                    HostTelnetConnectionDriver.TelnetSend(__Parameters.FtpServerIp + GlobalParameters.TelnetSendEndOfCommand); //Remote Host or IP Addr
                    s = HostTelnetConnectionDriver.TelnetWaitFor("Remote User Name");
                    HostTelnetConnectionDriver.LogIncommingStream(s);

                    HostTelnetConnectionDriver.TelnetSend(__Parameters.FtpServerUsername + GlobalParameters.TelnetSendEndOfCommand); //Remote User Name
                    s = HostTelnetConnectionDriver.TelnetWaitFor("Remote User Password");
                    HostTelnetConnectionDriver.LogIncommingStream(s);

                    HostTelnetConnectionDriver.TelnetSend(__Parameters.FtpServerPassword + GlobalParameters.TelnetSendEndOfCommand); //Remote User Password
                    s = HostTelnetConnectionDriver.TelnetWaitFor("Choice");
                    HostTelnetConnectionDriver.LogIncommingStream(s);

                    HostTelnetConnectionDriver.TelnetSend(GetFtpTransferModeNumber(__Parameters.FtpServerTransferMode) + GlobalParameters.TelnetSendEndOfCommand); //FtpTransferMode Text=0/Binary=1
                    s = HostTelnetConnectionDriver.TelnetWaitFor("Filename");
                    HostTelnetConnectionDriver.LogIncommingStream(s);

                    //figure out the file name
                    string _DestinationFileName = _ReportsList[i];
                    if (!string.IsNullOrEmpty(__Parameters.FtpDestinationFileNameTemplate))
                    {
                        _DestinationFileName = __Parameters.FtpDestinationFileNameTemplate;
                        if (i > 1) _DestinationFileName += "." + i.ToString();
                    }

                    //append the folder name if not empty
                    if (!string.IsNullOrEmpty(__Parameters.FtpServerFolderName))
                        _DestinationFileName = __Parameters.FtpServerFolderName + _DestinationFileName;

                    HostTelnetConnectionDriver.TelnetSend(_DestinationFileName + GlobalParameters.TelnetSendEndOfCommand); //Filename
                    s = HostTelnetConnectionDriver.TelnetWaitFor("Proceed With Transfer?");
                    HostTelnetConnectionDriver.LogIncommingStream(s);

                    HostTelnetConnectionDriver.TelnetSend("Y" + GlobalParameters.TelnetSendEndOfCommand); //Proceed With Transfer?

                    this.HandleFtpTransfer(s);
                }
            }
            catch (Exception e)
            {
                if (e is Dart.Telnet.DataException)
                    s = HostTelnetConnectionDriver.LogIncommingStream(((Dart.Telnet.DataException)e).DataRead.ToString());
                else
                    s = HostTelnetConnectionDriver.LogIncommingStream(string.Empty);
                HostTelnetConnectionDriver.HandleException(e, s);
            }
            finally
            {
                HostTelnetConnectionDriver.TelnetCloseConnection();
            }
        }

        /// <summary>
        /// Implements PC Interface Control -> Letter File to PC
        /// Moves Letter file to PC using FTP
        /// </summary>
        public void LetterFileToPc()
        {
            string s = "";

            try
            {
                HostTelnetConnectionDriver.Login();

                HostTelnetConnectionDriver.TelnetSend("8" + GlobalParameters.TelnetSendEndOfCommand); //Management Menu
                s = HostTelnetConnectionDriver.TelnetWaitFor("Menu Selection");
                HostTelnetConnectionDriver.LogIncommingStream(s);

                HostTelnetConnectionDriver.TelnetSend("2" + GlobalParameters.TelnetSendEndOfCommand); //PC Interface Control
                s = HostTelnetConnectionDriver.TelnetWaitFor("Choice");
                HostTelnetConnectionDriver.LogIncommingStream(s);

                HostTelnetConnectionDriver.TelnetSend("1" + GlobalParameters.TelnetSendEndOfCommand); //Letter File to PC
                s = HostTelnetConnectionDriver.TelnetWaitFor("Letter File Name");
                HostTelnetConnectionDriver.LogIncommingStream(s);

                HostTelnetConnectionDriver.TelnetSend(__Parameters.FileName + GlobalParameters.TelnetSendEndOfCommand); //Filename
                s = HostTelnetConnectionDriver.TelnetWaitFor(new string[] { "Transfer Mode", "No such file or directory" });
                s = HostTelnetConnectionDriver.LogIncommingStream(s);

                if (s.Contains("No such file or directory")) throw new ReturnException("430 Error: Letter File '" + __Parameters.FileName + "' does not exist");

                HostTelnetConnectionDriver.TelnetSend("2" + GlobalParameters.TelnetSendEndOfCommand); //Transfer Mode
                s = HostTelnetConnectionDriver.TelnetWaitFor("Transfer Reports Listed in This Report?");
                HostTelnetConnectionDriver.LogIncommingStream(s);

                HostTelnetConnectionDriver.TelnetSend("N" + GlobalParameters.TelnetSendEndOfCommand); //Transfer Reports Listed in This Report?
                s = HostTelnetConnectionDriver.TelnetWaitFor("Remote Host or IP Addr");
                HostTelnetConnectionDriver.LogIncommingStream(s);

                HostTelnetConnectionDriver.TelnetSend(__Parameters.FtpServerIp + GlobalParameters.TelnetSendEndOfCommand); //Remote Host or IP Addr
                s = HostTelnetConnectionDriver.TelnetWaitFor("Remote User Name");
                HostTelnetConnectionDriver.LogIncommingStream(s);

                HostTelnetConnectionDriver.TelnetSend(__Parameters.FtpServerUsername + GlobalParameters.TelnetSendEndOfCommand); //Remote User Name
                s = HostTelnetConnectionDriver.TelnetWaitFor("Remote User Password");
                HostTelnetConnectionDriver.LogIncommingStream(s);

                HostTelnetConnectionDriver.TelnetSend(__Parameters.FtpServerPassword + GlobalParameters.TelnetSendEndOfCommand); //Remote User Password
                s = HostTelnetConnectionDriver.TelnetWaitFor("Choice");
                HostTelnetConnectionDriver.LogIncommingStream(s);

                HostTelnetConnectionDriver.TelnetSend(GetFtpTransferModeNumber(__Parameters.FtpServerTransferMode) + GlobalParameters.TelnetSendEndOfCommand); //FtpTransferMode Text=0/Binary=1
                s = HostTelnetConnectionDriver.TelnetWaitFor("Filename");
                HostTelnetConnectionDriver.LogIncommingStream(s);

                string _FileName = __Parameters.FileName;
                //append the folder name if not empty
                if (!string.IsNullOrEmpty(__Parameters.FtpServerFolderName))
                    _FileName = __Parameters.FtpServerFolderName + _FileName;

                HostTelnetConnectionDriver.TelnetSend(_FileName + GlobalParameters.TelnetSendEndOfCommand); //Filename
                s = HostTelnetConnectionDriver.TelnetWaitFor("Proceed With Transfer?");
                HostTelnetConnectionDriver.LogIncommingStream(s);

                HostTelnetConnectionDriver.TelnetSend("Y" + GlobalParameters.TelnetSendEndOfCommand); //Proceed With Transfer?

                this.HandleFtpTransfer(s);
                
            }
            catch (Exception e)
            {
                if (e is Dart.Telnet.DataException)
                    s = HostTelnetConnectionDriver.LogIncommingStream(((Dart.Telnet.DataException)e).DataRead.ToString());
                else
                    s = HostTelnetConnectionDriver.LogIncommingStream(string.Empty);
                HostTelnetConnectionDriver.HandleException(e, s);
            }
            finally
            {
                HostTelnetConnectionDriver.TelnetCloseConnection();
            }
        }

        /// <summary>
        /// Implements PC Interface Control -> Data File to PC
        /// Moves Data file to PC using FTP
        /// </summary>
        public void DataFileToPc()
        {
            string s = "";

            try
            {
                HostTelnetConnectionDriver.Login();

                HostTelnetConnectionDriver.TelnetSend("8" + GlobalParameters.TelnetSendEndOfCommand); //Management Menu
                s = HostTelnetConnectionDriver.TelnetWaitFor("Menu Selection");
                HostTelnetConnectionDriver.LogIncommingStream(s);

                HostTelnetConnectionDriver.TelnetSend("2" + GlobalParameters.TelnetSendEndOfCommand); //PC Interface Control
                s = HostTelnetConnectionDriver.TelnetWaitFor("Choice");
                HostTelnetConnectionDriver.LogIncommingStream(s);

                HostTelnetConnectionDriver.TelnetSend("6" + GlobalParameters.TelnetSendEndOfCommand); //Data File to PC
                s = HostTelnetConnectionDriver.TelnetWaitFor("Data File Name");
                HostTelnetConnectionDriver.LogIncommingStream(s);

                HostTelnetConnectionDriver.TelnetSend(__Parameters.FileName + GlobalParameters.TelnetSendEndOfCommand); //Filename
                s = HostTelnetConnectionDriver.TelnetWaitFor(new string[] { "Transfer Mode", "No such file or directory" });
                s = HostTelnetConnectionDriver.LogIncommingStream(s);

                if (s.Contains("No such file or directory")) throw new ReturnException("430 Error: Data File '" + __Parameters.FileName + "' does not exist");

                HostTelnetConnectionDriver.TelnetSend("2" + GlobalParameters.TelnetSendEndOfCommand); //Transfer Mode
                s = HostTelnetConnectionDriver.TelnetWaitFor("Transfer Reports Listed in This Report?");
                HostTelnetConnectionDriver.LogIncommingStream(s);

                HostTelnetConnectionDriver.TelnetSend("N" + GlobalParameters.TelnetSendEndOfCommand); //Transfer Reports Listed in This Report?
                s = HostTelnetConnectionDriver.TelnetWaitFor("Remote Host or IP Addr");
                HostTelnetConnectionDriver.LogIncommingStream(s);

                HostTelnetConnectionDriver.TelnetSend(__Parameters.FtpServerIp + GlobalParameters.TelnetSendEndOfCommand); //Remote Host or IP Addr
                s = HostTelnetConnectionDriver.TelnetWaitFor("Remote User Name");
                HostTelnetConnectionDriver.LogIncommingStream(s);

                HostTelnetConnectionDriver.TelnetSend(__Parameters.FtpServerUsername + GlobalParameters.TelnetSendEndOfCommand); //Remote User Name
                s = HostTelnetConnectionDriver.TelnetWaitFor("Remote User Password");
                HostTelnetConnectionDriver.LogIncommingStream(s);

                HostTelnetConnectionDriver.TelnetSend(__Parameters.FtpServerPassword + GlobalParameters.TelnetSendEndOfCommand); //Remote User Password
                s = HostTelnetConnectionDriver.TelnetWaitFor("Choice");
                HostTelnetConnectionDriver.LogIncommingStream(s);

                HostTelnetConnectionDriver.TelnetSend(GetFtpTransferModeNumber(__Parameters.FtpServerTransferMode) + GlobalParameters.TelnetSendEndOfCommand); //FtpTransferMode Text=0/Binary=1
                s = HostTelnetConnectionDriver.TelnetWaitFor("Filename");
                HostTelnetConnectionDriver.LogIncommingStream(s);

                string _FileName = __Parameters.FileName;
                //append the folder name if not empty
                if (!string.IsNullOrEmpty(__Parameters.FtpServerFolderName))
                    _FileName = __Parameters.FtpServerFolderName + _FileName;

                HostTelnetConnectionDriver.TelnetSend(_FileName + GlobalParameters.TelnetSendEndOfCommand); //Filename
                s = HostTelnetConnectionDriver.TelnetWaitFor("Proceed With Transfer?");
                HostTelnetConnectionDriver.LogIncommingStream(s);

                HostTelnetConnectionDriver.TelnetSend("Y" + GlobalParameters.TelnetSendEndOfCommand); //Proceed With Transfer?

                this.HandleFtpTransfer(s);

            }
            catch (Exception e)
            {
                if (e is Dart.Telnet.DataException)
                    s = HostTelnetConnectionDriver.LogIncommingStream(((Dart.Telnet.DataException)e).DataRead.ToString());
                else
                    s = HostTelnetConnectionDriver.LogIncommingStream(string.Empty);
                HostTelnetConnectionDriver.HandleException(e, s);
            }
            finally
            {
                HostTelnetConnectionDriver.TelnetCloseConnection();
            }
        }

        /// <summary>
        /// Implements PC Interface Control -> PC to Edit File
        /// Moves the local file to Edit File using FTP
        /// </summary>
        public void PcToEditFile()
        {
            string s = "";

            try
            {
                HostTelnetConnectionDriver.Login();

                HostTelnetConnectionDriver.TelnetSend("8" + GlobalParameters.TelnetSendEndOfCommand); //Management Menu
                s = HostTelnetConnectionDriver.TelnetWaitFor("Menu Selection");
                HostTelnetConnectionDriver.LogIncommingStream(s);


                HostTelnetConnectionDriver.TelnetSend("2" + GlobalParameters.TelnetSendEndOfCommand); //PC Interface Control
                s = HostTelnetConnectionDriver.TelnetWaitFor("Choice");
                HostTelnetConnectionDriver.LogIncommingStream(s);

                HostTelnetConnectionDriver.TelnetSend("9" + GlobalParameters.TelnetSendEndOfCommand); //PC to Edit File
                s = HostTelnetConnectionDriver.TelnetWaitFor(new string[] { "Transfer Mode", "Edit File Already Exists" });
                s = HostTelnetConnectionDriver.LogIncommingStream(s);

                if (s.Contains("Edit File Already Exists")) throw new ReturnException("435 Error: Edit File location on Destination SYM already has a file. Delete the Edit File and try again. Aborting Process.");

                HostTelnetConnectionDriver.TelnetSend("2" + GlobalParameters.TelnetSendEndOfCommand); //Transfer Mode
                s = HostTelnetConnectionDriver.TelnetWaitFor("Remote Host or IP Addr");
                HostTelnetConnectionDriver.LogIncommingStream(s);

                HostTelnetConnectionDriver.TelnetSend(__Parameters.FtpServerIp + GlobalParameters.TelnetSendEndOfCommand); //Remote Host or IP Addr
                s = HostTelnetConnectionDriver.TelnetWaitFor("Remote User Name");
                HostTelnetConnectionDriver.LogIncommingStream(s);

                HostTelnetConnectionDriver.TelnetSend(__Parameters.FtpServerUsername + GlobalParameters.TelnetSendEndOfCommand); //Remote User Name
                s = HostTelnetConnectionDriver.TelnetWaitFor("Remote User Password");
                HostTelnetConnectionDriver.LogIncommingStream(s);

                HostTelnetConnectionDriver.TelnetSend(__Parameters.FtpServerPassword + GlobalParameters.TelnetSendEndOfCommand); //Remote User Password
                s = HostTelnetConnectionDriver.TelnetWaitFor("Choice");
                HostTelnetConnectionDriver.LogIncommingStream(s);

                HostTelnetConnectionDriver.TelnetSend(GetFtpTransferModeNumber(__Parameters.FtpServerTransferMode) + GlobalParameters.TelnetSendEndOfCommand); //FtpTransferMode Text=0/Binary=1
                s = HostTelnetConnectionDriver.TelnetWaitFor("Filename");
                HostTelnetConnectionDriver.LogIncommingStream(s);

                string _FileName = __Parameters.FileName;
                //append the folder name if not empty
                if (!string.IsNullOrEmpty(__Parameters.FtpServerFolderName))
                    _FileName = __Parameters.FtpServerFolderName + _FileName;

                HostTelnetConnectionDriver.TelnetSend(_FileName + GlobalParameters.TelnetSendEndOfCommand); //Filename
                s = HostTelnetConnectionDriver.TelnetWaitFor("Proceed With Transfer?");
                HostTelnetConnectionDriver.LogIncommingStream(s);

                HostTelnetConnectionDriver.TelnetSend("Y" + GlobalParameters.TelnetSendEndOfCommand); //Proceed With Tranfer?

                this.HandleFtpTransfer(s);
            }
            catch (Exception e)
            {
                if (e is Dart.Telnet.DataException)
                    s = HostTelnetConnectionDriver.LogIncommingStream(((Dart.Telnet.DataException)e).DataRead.ToString());
                else
                    s = HostTelnetConnectionDriver.LogIncommingStream(string.Empty);
                HostTelnetConnectionDriver.HandleException(e, s);
            }
            finally
            {
                HostTelnetConnectionDriver.TelnetCloseConnection();
            }
        }

        /// <summary>
        /// Implements PC Interface Control -> PC to Edit File
        /// Moves the local file to Edit File using FTP
        /// </summary>
        public void PcToLetterFile()
        {
            string s = "";

            try
            {
                HostTelnetConnectionDriver.Login();

                HostTelnetConnectionDriver.TelnetSend("8" + GlobalParameters.TelnetSendEndOfCommand); //Management Menu
                s = HostTelnetConnectionDriver.TelnetWaitFor("Menu Selection");
                HostTelnetConnectionDriver.LogIncommingStream(s);

                HostTelnetConnectionDriver.TelnetSend("2" + GlobalParameters.TelnetSendEndOfCommand); //PC Interface Control
                s = HostTelnetConnectionDriver.TelnetWaitFor("Choice");
                HostTelnetConnectionDriver.LogIncommingStream(s);

                HostTelnetConnectionDriver.TelnetSend("8" + GlobalParameters.TelnetSendEndOfCommand); //PC to Letter File
                s = HostTelnetConnectionDriver.TelnetWaitFor("Transfer Mode");
                HostTelnetConnectionDriver.LogIncommingStream(s);

                HostTelnetConnectionDriver.TelnetSend("2" + GlobalParameters.TelnetSendEndOfCommand); //Transfer Mode
                s = HostTelnetConnectionDriver.TelnetWaitFor("Remote Host or IP Addr");
                HostTelnetConnectionDriver.LogIncommingStream(s);

                HostTelnetConnectionDriver.TelnetSend(__Parameters.FtpServerIp + GlobalParameters.TelnetSendEndOfCommand); //Remote Host or IP Addr
                s = HostTelnetConnectionDriver.TelnetWaitFor("Remote User Name");
                HostTelnetConnectionDriver.LogIncommingStream(s);

                HostTelnetConnectionDriver.TelnetSend(__Parameters.FtpServerUsername + GlobalParameters.TelnetSendEndOfCommand); //Remote User Name
                s = HostTelnetConnectionDriver.TelnetWaitFor("Remote User Password");
                HostTelnetConnectionDriver.LogIncommingStream(s);

                HostTelnetConnectionDriver.TelnetSend(__Parameters.FtpServerPassword + GlobalParameters.TelnetSendEndOfCommand); //Remote User Password
                s = HostTelnetConnectionDriver.TelnetWaitFor("Choice");
                HostTelnetConnectionDriver.LogIncommingStream(s);

                HostTelnetConnectionDriver.TelnetSend(GetFtpTransferModeNumber(__Parameters.FtpServerTransferMode) + GlobalParameters.TelnetSendEndOfCommand); //FtpTransferMode Text=0/Binary=1
                s = HostTelnetConnectionDriver.TelnetWaitFor("Source File Name to Upload");
                HostTelnetConnectionDriver.LogIncommingStream(s);

                string _FileName = __Parameters.FileName;
                //append the folder name if not empty
                if (!string.IsNullOrEmpty(__Parameters.FtpServerFolderName))
                    _FileName = __Parameters.FtpServerFolderName + _FileName;

                HostTelnetConnectionDriver.TelnetSend(_FileName + GlobalParameters.TelnetSendEndOfCommand); //Source File Name to Upload
                s = HostTelnetConnectionDriver.TelnetWaitFor("Destination File Name on Local System");
                HostTelnetConnectionDriver.LogIncommingStream(s);

                HostTelnetConnectionDriver.TelnetSend("" + GlobalParameters.TelnetSendEndOfCommand); //Destination File Name on Local System          
                s = HostTelnetConnectionDriver.TelnetWaitFor("Proceed With Transfer?");
                HostTelnetConnectionDriver.LogIncommingStream(s);

                HostTelnetConnectionDriver.TelnetSend("Y" + GlobalParameters.TelnetSendEndOfCommand); //Proceed With Tranfer?

                this.HandleFtpTransfer(s);
            }
            catch (Exception e)
            {
                if (e is Dart.Telnet.DataException)
                    s = HostTelnetConnectionDriver.LogIncommingStream(((Dart.Telnet.DataException)e).DataRead.ToString());
                else
                    s = HostTelnetConnectionDriver.LogIncommingStream(string.Empty);
                HostTelnetConnectionDriver.HandleException(e, s);
            }
            finally
            {
                HostTelnetConnectionDriver.TelnetCloseConnection();
            }
        }

        /// <summary>
        /// Implements PC Interface Control -> PC to Data File
        /// Moves the local file to Data File using FTP
        /// </summary>
        public void PcToDataFile()
        {
            string s = "";

            try
            {
                HostTelnetConnectionDriver.Login();

                HostTelnetConnectionDriver.TelnetSend("8" + GlobalParameters.TelnetSendEndOfCommand); //Management Menu
                s = HostTelnetConnectionDriver.TelnetWaitFor("Menu Selection");
                HostTelnetConnectionDriver.LogIncommingStream(s);


                HostTelnetConnectionDriver.TelnetSend("2" + GlobalParameters.TelnetSendEndOfCommand); //PC Interface Control
                s = HostTelnetConnectionDriver.TelnetWaitFor("Choice");
                HostTelnetConnectionDriver.LogIncommingStream(s);

                HostTelnetConnectionDriver.TelnetSend("12" + GlobalParameters.TelnetSendEndOfCommand); //PC to Data File
                s = HostTelnetConnectionDriver.TelnetWaitFor("Transfer Mode");
                HostTelnetConnectionDriver.LogIncommingStream(s);

                HostTelnetConnectionDriver.TelnetSend("2" + GlobalParameters.TelnetSendEndOfCommand); //Transfer Mode
                s = HostTelnetConnectionDriver.TelnetWaitFor("Remote Host or IP Addr");
                HostTelnetConnectionDriver.LogIncommingStream(s);

                HostTelnetConnectionDriver.TelnetSend(__Parameters.FtpServerIp + GlobalParameters.TelnetSendEndOfCommand); //Remote Host or IP Addr
                s = HostTelnetConnectionDriver.TelnetWaitFor("Remote User Name");
                HostTelnetConnectionDriver.LogIncommingStream(s);

                HostTelnetConnectionDriver.TelnetSend(__Parameters.FtpServerUsername + GlobalParameters.TelnetSendEndOfCommand); //Remote User Name
                s = HostTelnetConnectionDriver.TelnetWaitFor("Remote User Password");
                HostTelnetConnectionDriver.LogIncommingStream(s);

                HostTelnetConnectionDriver.TelnetSend(__Parameters.FtpServerPassword + GlobalParameters.TelnetSendEndOfCommand); //Remote User Password
                s = HostTelnetConnectionDriver.TelnetWaitFor("Choice");
                HostTelnetConnectionDriver.LogIncommingStream(s);

                HostTelnetConnectionDriver.TelnetSend(GetFtpTransferModeNumber(__Parameters.FtpServerTransferMode) + GlobalParameters.TelnetSendEndOfCommand); //FtpTransferMode Text=0/Binary=1
                s = HostTelnetConnectionDriver.TelnetWaitFor("Source File Name to Upload");
                HostTelnetConnectionDriver.LogIncommingStream(s);

                string _FileName = __Parameters.FileName;
                //append the folder name if not empty
                if (!string.IsNullOrEmpty(__Parameters.FtpServerFolderName))
                    _FileName = __Parameters.FtpServerFolderName + _FileName;

                HostTelnetConnectionDriver.TelnetSend(_FileName + GlobalParameters.TelnetSendEndOfCommand); //Source File Name to Upload
                s = HostTelnetConnectionDriver.TelnetWaitFor("Destination File Name on Local System");
                HostTelnetConnectionDriver.LogIncommingStream(s);

                HostTelnetConnectionDriver.TelnetSend("" + GlobalParameters.TelnetSendEndOfCommand); //Destination File Name on Local System          
                s = HostTelnetConnectionDriver.TelnetWaitFor("Proceed With Transfer?");
                HostTelnetConnectionDriver.LogIncommingStream(s);

                HostTelnetConnectionDriver.TelnetSend("Y" + GlobalParameters.TelnetSendEndOfCommand); //Proceed With Tranfer?

                this.HandleFtpTransfer(s);
            }
            catch (Exception e)
            {
                if (e is Dart.Telnet.DataException)
                    s = HostTelnetConnectionDriver.LogIncommingStream(((Dart.Telnet.DataException)e).DataRead.ToString());
                else
                    s = HostTelnetConnectionDriver.LogIncommingStream(string.Empty);
                HostTelnetConnectionDriver.HandleException(e, s);
            }
            finally
            {
                HostTelnetConnectionDriver.TelnetCloseConnection();
            }
        }

        /// <summary>
        /// Handles the ftp transfer
        /// </summary>
        /// <param name="s"></param>
        private void HandleFtpTransfer(string s)
        {
            //this will check the output every 5 seconds
            HostTelnetConnectionDriver.TelnetChangeTimeout(5);
            int _TimeElapsed = 0;
            bool _TransferCompleted = false;
            while (_TimeElapsed < __Parameters.FtpServerTimoutoutInSec && !_TransferCompleted)
            {
                try
                {
                    s = HostTelnetConnectionDriver.TelnetWaitFor("226 Transfer OK");
                    HostTelnetConnectionDriver.LogIncommingStream(s);
                    _TransferCompleted = true;
                }
                catch (Dart.Telnet.DataException _DataException)
                {
                    s = HostTelnetConnectionDriver.LogIncommingStream(_DataException.DataRead.ToString());

                    //regex will look for start of string, 226, space, one or more non-greedy characters and "transfer" on the same line
                    if (Regex.IsMatch(s, @"^226\s.*?transfer", RegexOptions.Multiline | RegexOptions.IgnoreCase))
                    {
                        _TransferCompleted = true;
                    }

                    //these are the most common error message; otherwise generic timeout will be displayed after the full timeout period
                    if (!_TransferCompleted &&
                        (s.ToLower().Contains("goodbye") || 
                         s.ToLower().Contains("connection refused") || 
                         s.ToLower().Contains("login or password incorrect") ||
                         s.ToLower().Contains("permission denied")))
                    {
                        throw new ReturnException("421 Error: FTP Transfer Failed " + Environment.NewLine + HostTelnetConnectionDriver.RemoveNonPrintableCharacters(s));
                    }
                }
                _TimeElapsed = _TimeElapsed + 5;
            }
            HostTelnetConnectionDriver.TelnetChangeTimeout(HostTelnetConnectionDriver.Parameters.TelnetCommandsTimeoutInSec);

            if (!_TransferCompleted)
            {
                throw new ReturnException("425 Error: Ftp Transfer timed out.");
            }
        }

        /// <summary>
        /// Gets the most recent Batch ouput sequence number for the specifed JobFileName
        /// </summary>
        /// <param name="_JobFileName"></param>
        /// <returns></returns>
        private string GetBatchSequenceNumber(string _JobFileName)
        {
            string s = "";

            HostTelnetConnectionDriver.TelnetSend("8" + GlobalParameters.TelnetSendEndOfCommand); //Management Menu
            s = HostTelnetConnectionDriver.TelnetWaitFor("Menu Selection");
            HostTelnetConnectionDriver.LogIncommingStream(s);

            HostTelnetConnectionDriver.TelnetSend("1" + GlobalParameters.TelnetSendEndOfCommand); //Print Control
            s = HostTelnetConnectionDriver.TelnetWaitFor("Printing Control Command");
            HostTelnetConnectionDriver.LogIncommingStream(s);

            HostTelnetConnectionDriver.TelnetSend("L" + GlobalParameters.TelnetSendEndOfCommand); //Printing Control Command
            s = HostTelnetConnectionDriver.TelnetWaitFor("List Reports");
            HostTelnetConnectionDriver.LogIncommingStream(s);

            //give the list command 5 more seconds than usual to respond;
            HostTelnetConnectionDriver.TelnetChangeTimeout(HostTelnetConnectionDriver.Parameters.TelnetCommandsTimeoutInSec + 5);

            HostTelnetConnectionDriver.TelnetSend("" + GlobalParameters.TelnetSendEndOfCommand); //Recent Reports
            s = HostTelnetConnectionDriver.TelnetWaitFor("Printing Control Command");
            HostTelnetConnectionDriver.LogIncommingStream(s);

            //reset the timeout
            HostTelnetConnectionDriver.TelnetChangeTimeout(HostTelnetConnectionDriver.Parameters.TelnetCommandsTimeoutInSec);

            //now parse out the "[Sequence Number] Batch Output for [Jobfile Name]" from the text received
            System.Text.RegularExpressions.MatchCollection _MatchCollection;
            System.Text.RegularExpressions.Regex _Regex = new System.Text.RegularExpressions.Regex(@"(\d+) Batch Output for " + _JobFileName, System.Text.RegularExpressions.RegexOptions.IgnoreCase);
            _MatchCollection = _Regex.Matches(s);
            if (_MatchCollection.Count > 0)
            {
                return _MatchCollection[_MatchCollection.Count - 1].Groups[1].Value;
            }
            else
            {
                throw new ReturnException("423 Error: Batch Report not found for Jobfile '" + _JobFileName + "'.");
            }
        }

        /// <summary>
        /// Gets the reports genenrated for BatchFileSequenceNumber
        /// </summary>
        /// <param name="_BatchFileSequenceNumber"></param>
        /// <param name="_FtpJobFileReportTitle">Only return reports (filter) mathing this title</param>
        /// <returns></returns>
        private List<string> GetReportsForBatchSequence(string _BatchFileSequenceNumber, string _FtpJobFileReportTitle)
        {
            List<string> _ReportsList = new List<string>();
            string s = "";

            HostTelnetConnectionDriver.TelnetSend("8" + GlobalParameters.TelnetSendEndOfCommand); //Management Menu
            s = HostTelnetConnectionDriver.TelnetWaitFor("Menu Selection");
            HostTelnetConnectionDriver.LogIncommingStream(s);

            HostTelnetConnectionDriver.TelnetSend("1" + GlobalParameters.TelnetSendEndOfCommand); //Print Control
            s = HostTelnetConnectionDriver.TelnetWaitFor("Printing Control Command");
            HostTelnetConnectionDriver.LogIncommingStream(s);

            HostTelnetConnectionDriver.TelnetSend("V" + GlobalParameters.TelnetSendEndOfCommand); //Printing Control Command - View Report
            s = HostTelnetConnectionDriver.TelnetWaitFor("Report to View");
            HostTelnetConnectionDriver.LogIncommingStream(s);

            HostTelnetConnectionDriver.TelnetSend(_BatchFileSequenceNumber + GlobalParameters.TelnetSendEndOfCommand); //Report to View
            s = HostTelnetConnectionDriver.TelnetWaitFor("From Page");
            HostTelnetConnectionDriver.LogIncommingStream(s);

            HostTelnetConnectionDriver.TelnetSend("" + GlobalParameters.TelnetSendEndOfCommand); //From Page
            s = HostTelnetConnectionDriver.TelnetWaitFor("To   Page");
            HostTelnetConnectionDriver.LogIncommingStream(s);

            HostTelnetConnectionDriver.TelnetSend("" + GlobalParameters.TelnetSendEndOfCommand); //To Page
            s = HostTelnetConnectionDriver.TelnetWaitFor("Selection");
            HostTelnetConnectionDriver.LogIncommingStream(s);

            HostTelnetConnectionDriver.TelnetSend("0" + GlobalParameters.TelnetSendEndOfCommand); //Selection - Display both sides
            string _BatchFileText = string.Empty;
            //there could be more than one page to the report so we need to keep hitting {enter} key until "Printing Control Command" is found
            for (int i = 0; i < 100; i++)
            {
                HostTelnetConnectionDriver.TelnetChangeTimeout(2);
                try
                {
                    s = HostTelnetConnectionDriver.TelnetWaitFor("Printing Control Command");
                    //if "Printing Control Command" is found then break out of the loop
                    _BatchFileText += HostTelnetConnectionDriver.LogIncommingStream(s);
                    break;
                }
                //not the best way to do it but there are more pages to read
                catch (Dart.Telnet.DataException _DataException)
                {
                    _BatchFileText += HostTelnetConnectionDriver.LogIncommingStream(_DataException.DataRead.ToString());
                    HostTelnetConnectionDriver.TelnetSend("" + GlobalParameters.TelnetSendEndOfCommand); //send {enter}
                }
                finally
                {
                    HostTelnetConnectionDriver.TelnetChangeTimeout(HostTelnetConnectionDriver.Parameters.TelnetCommandsTimeoutInSec);
                }
            }

            //now parse out the "Seq:[One or More spaces][Sequence Number][One or More spaces]Pages:" from the text received
            System.Text.RegularExpressions.MatchCollection _MatchCollection;
            System.Text.RegularExpressions.Regex _Regex = new System.Text.RegularExpressions.Regex(@"Seq:\s+(\d+)\s+Pages", System.Text.RegularExpressions.RegexOptions.IgnoreCase);

            //if a Report Title name is specified then modify the regex to only search for that report title
            if (!string.IsNullOrEmpty(_FtpJobFileReportTitle))
            {
                //this will match Seq:[One or More spaces][Sequence Number][One or More spaces]Pages:[One or More Spaces][One or More Numbers][One or More spaces]Title:[One or More Spaces][Title of the Report][Zero or More spaces][End of Line]"
                _Regex = new System.Text.RegularExpressions.Regex(@"Seq:\s+(\d+)\s+Pages:\s+\d+\s+Title:\s+" + _FtpJobFileReportTitle + @"\s*\n", System.Text.RegularExpressions.RegexOptions.IgnoreCase);
            }

            _MatchCollection = _Regex.Matches(_BatchFileText);
            for (int i = 0; i < _MatchCollection.Count; i++)
            {
                _ReportsList.Add(_MatchCollection[i].Groups[1].Value);
            }

            if (_MatchCollection.Count == 0)
            {
                throw new ReturnException("424 Error: No matching Reports found for Batch Report Sequence number '" + _BatchFileSequenceNumber + "'.");
            }

            return _ReportsList;
        }

        /// <summary>
        /// Returns parsed out list for string ReportSequenceList
        /// </summary>
        /// <param name="_ReportSequenceList"></param>
        /// <returns></returns>
        private List<string> GetReportsForList(string _ReportSequenceList)
        {
            List<string> _ReportsList = new List<string>();
            return ValidateReportSequenceList(_ReportSequenceList, ref _ReportsList) == null ? _ReportsList : null;
        }

        /// <summary>
        /// Parses the string from _ReportSequenceList. Error string is returned as the return value.
        /// </summary>
        /// <param name="_ReportSequenceList"></param>
        /// <param name="_ReportsList"></param>
        /// <returns>Error Text</returns>
        public static string ValidateReportSequenceList(string _ReportSequenceList, ref List<string> _ReportsList)
        {
            int _SequenceNumberSize = 0;

            string[] _ReportGroup = _ReportSequenceList.Split(',');
            foreach (string _ReportGroupItem in _ReportGroup)
            {
                if (_ReportGroupItem == string.Empty)
                {
                    return "ReportGroup cannot be empty";
                }

                string[] _ReportGroupSub = _ReportGroupItem.Split('-');
                if (_ReportGroupSub.Length > 2)
                {
                    return "ReportGroup format must be StartingSequence-EndingSequence";
                }
                else if (_ReportGroupSub.Length == 1)
                {
                    int _SequenceNumber;
                    if (!int.TryParse(_ReportGroupSub[0], out _SequenceNumber))
                    {
                        return "Sequence Number must be able to be parsed as integer";
                    }

                    //detect sequnce number length
                    _SequenceNumberSize = _SequenceNumberSize == 0 ? _ReportGroupSub[0].Trim().Length : _SequenceNumberSize;
                    
                    //add to the collection
                    _ReportsList.Add(_SequenceNumber.ToString().PadLeft(_SequenceNumberSize, '0'));

                }
                else if (_ReportGroupSub.Length == 2)
                {
                    int _StartingSequenceNumber;
                    int _EndingSequenceNumber;
                    if (!int.TryParse(_ReportGroupSub[0], out _StartingSequenceNumber) || !int.TryParse(_ReportGroupSub[1], out _EndingSequenceNumber))
                    {
                        return "Sequence Number must be able to be parsed as integer";
                    }

                    if (_StartingSequenceNumber > _EndingSequenceNumber)
                    {
                        return "For any SequenceNumberGroup EndingSequenceNumber must be greater or equal to StartingSequenceNumber";
                    }

                    //detect sequnce number length
                    _SequenceNumberSize = _SequenceNumberSize == 0 ? _ReportGroupSub[0].Trim().Length : _SequenceNumberSize;

                    //add to collection
                    for (int _SequenceNumber = _StartingSequenceNumber; _SequenceNumber <= _EndingSequenceNumber; _SequenceNumber++)
                    {
                        _ReportsList.Add(_SequenceNumber.ToString().PadLeft(_SequenceNumberSize, '0'));
                    }
                }
            }

            return null;
        }

        /// <summary>
        /// Returns the number 0 or 1 based on if the input parameter is binary or ascii
        /// </summary>
        /// <param name="_FtpTransferMode">binary or ascii</param>
        /// <returns></returns>
        public static string GetFtpTransferModeNumber(string _FtpTransferMode)
        {
            if (_FtpTransferMode == "binary") return "1";
            else if (_FtpTransferMode == "ascii") return "0";
            else throw new ReturnException("422 Error: Invalid value for FtpTransferMode. Value values are ascii,binary.");
        }
    }
}
